#ifndef _BUOLA_GL_COPENGLGC_H_
#define _BUOLA_GL_COPENGLGC_H_

#include <buola/image/cgc.h>
#include <buola/image/cpath.h>
#include <buola/mat/transformations.h>

#include <buola/gl/cglyphcache.h>
#include <buola/gl/cvbo.h>
#include <buola/gl/cprogram.h>
#include <buola/gl/cuniform.h>
#include <buola/gl/ccontext.h>
#include <buola/image/rasterizer/cscanlinerasterizer.h>
#include <buola/utility/cregion.h>

namespace buola { namespace gl {

class COpenGLGC : public img::CGC
{
public:
    COpenGLGC(CContext *pContext,bool pOwn=true);
    ~COpenGLGC();

    img::CSurface *Surface()      {   return mContext->Surface();    }

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//////////////////////////////// Interface ////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

public:
//////////////////
// drawing
//
    void Paint();
    void DoFill();
    void DoStroke();
    void DoClip();
    void DoResetClip();

/////////////////
// render text
//
    void DrawGlyphs(img::PFont pFont,img::TFontIndex pIndex,int *pIndices,int pN,
            const std::vector<img::CTextLayout::SGlyph> &pGlyphs,const CPoint_d &pPos);

///////////////////////
// image compositing
//
    void RenderImage(const CPoint_d &pPos,const img::CAnyView &pView);
    
    void Composite(const CPoint_d &pDstPoint,const CSize_d &pDstSize,const img::CPicture &pSrc,
                   const CPoint_d &pSrcPoint=nZero,const CSize_d &pSrcSize=nUndefined,
                   const img::CPicture &pMask=img::CPicture(),const CPoint_d &pMaskPoint=nZero,
                   const CSize_d &pMaskSize=nUndefined,img::EExtend pExtend=img::EExtend::NONE);

/////////////////
// GL-specific
//
    void SetExposeSize(const CSize_d &pSize);
    void MakeCurrent(img::CSurface* =nullptr);
    bool IsCurrent();
    void SwapBuffers();
    void SwapBuffers(const CRegion &pRegion,int pY);

private:
    void TransformGlyphs(img::CScaledFont *pFont,const std::vector<img::CGlyphShow> &pGlyphs,
                         img::CGlyphShow *pTransformed,int &pTransformedCount);

    gl::CGlyphCache *GetGlyphCache();
    
private:
    void Rasterize(img::CScanlineRasterizer<> &pRasterizer);
    void PrepareLinear();
    void PrepareRadial();
    void PrepareProgram();
////////////////////////////////////////
////////////////////////////////////////
///////////////// DATA /////////////////
////////////////////////////////////////
////////////////////////////////////////
    CContext *mContext;
    bool mOwnContext;
    CRect_d mExposeRect;

    gl::CVBO mVBO;
    gl::CVBOMap<float> mVBOMap;

    gl::CProgram mGlyphProgram;
    gl::CProgram mSolidProgram;
    gl::CProgram mLinearProgram;
    gl::CProgram mRadialProgram;
    gl::CProgram mImageProgram;
    gl::CUniform mGlyphTransformation;
    gl::CUniform mSolidTransformation;
    gl::CUniform mSolidColor;
    gl::CUniform uLinearTransformation;
    gl::CUniform uLinearOrigin;
    gl::CUniform uLinearDirection;
    gl::CUniform uLinearLength;
    gl::CUniform uRadialTransformation;
    gl::CUniform uRadial1;
    gl::CUniform uRadialD;
    gl::CUniform uRadialA;
    gl::CUniform mImageTransformation;
    gl::CTexture mGradientTexture;
    
    static gl::CGlyphCache *mGlyphCache;
    
    img::CScanlines mClipArea;
    bool mClip;
};

/*namespace gl*/ } /*namespace buola*/ }

#endif
